import type { ChatMessage, ConversationInfo } from './type'
import { ChatStoreName } from '@/provider/storage/enum'
import StorageProvider from '@/provider/storage'
import xModelService from '@/services/model'
import { geneUniqueID } from './hooks/utils'

// 会话数据存储，与聊天记录共通
interface DbConvs extends ConversationInfo {
  chats: ChatMessage[]
}

/**
 * 聊天服务类
 *
 * @description 管理聊天与会话相关功能
 */
class xChatService {
  // 静态属性存储唯一实例
  private static instance: xChatService

  /**
   * 服务初始化（全局仅执行一次）
   */
  private constructor() {}

  /**
   * 获取单例实例
   *
   * @returns
   */
  public static getInstance = () => {
    if (!xChatService.instance) {
      xChatService.instance = new xChatService()
    }
    return xChatService.instance
  }

  /**
   * 添加一条聊天记录（自动创建会话）
   *
   * @param convId 会话ID
   * @param role 角色
   * @param content 消息文本
   * @param attachs 附件
   * @returns
   */
  public addConvChatInfo = async (
    convId: string,
    role: ChatRole,
    content: string,
    attachs?: AttachFile[],
  ) => {
    const timestamp = Date.now()
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    let conv = await db.get(convId)
    if (!conv) {
      // 未创建会话，新增
      const modelSetting = xModelService.getInstance().readModelSetting()
      conv = {
        id: convId,
        title: '新对话',
        chats: [],
        timestamp,
      }
      if (modelSetting.prompt) {
        // 添加系统提示词
        conv.chats.push({
          id: geneUniqueID(),
          convId,
          role: 'system',
          content: modelSetting.prompt,
          timestamp,
        })
      }
    }
    // 添加聊天记录
    if (role === 'error') {
      content = '<error>' + content + '</error>'
    }
    const chatId = geneUniqueID()
    conv.chats.push({
      id: chatId,
      convId,
      role,
      content,
      attachs: attachs ?? undefined,
      timestamp,
    })
    await db.set(conv)
    return chatId
  }

  /**
   * 获取完整会话记录
   *
   * @returns
   */
  public getConvsHistory = async () => {
    const response: ConversationInfo[] = []
    // 读取存储的模型
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    const conversations = await db.getAll()
    for (const item of conversations) {
      response.push({
        id: item.id,
        title: item.title,
        isTop: !!item.isTop,
        timestamp: item.timestamp,
      })
    }
    // 排序
    return response.sort((a, b) => {
      if (a.isTop !== b.isTop) {
        return b.isTop ? 1 : -1
      }
      return b.timestamp - a.timestamp
    })
  }

  /**
   * 获取指定会话信息
   *
   * @param convId 会话ID
   * @returns
   */
  public getConvInfo = async (convId: string): Promise<ConversationInfo> => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    const conv = await db.get(convId)
    if (conv) {
      return {
        id: conv.id,
        title: conv.title,
        isTop: !!conv.isTop,
        timestamp: conv.timestamp,
      }
    }
  }

  /**
   * 修改指定会话信息
   *
   * @param convId 会话ID
   * @param data 会话数据（支持片段更新）
   * @returns
   */
  public setConvInfo = async (convId: string, data: Partial<Omit<ConversationInfo, 'id'>>) => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    const conv = await db.get(convId)
    if (!conv) {
      throw new Error('未找到会话信息')
    }
    // 保证ID不会变更，更新时间戳
    Object.assign(conv, data, { id: convId })
    await db.set(conv)
    return conv
  }

  /**
   * 删除指定会话信息（包含聊天）
   *
   * @param convId 会话ID
   * @returns
   */
  public delConvInfo = async (convId: string | string[]) => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    return db.delete(convId)
  }

  /**
   * 清空全部会话信息（包含聊天）
   *
   * @returns
   */
  public clearAllConvs = async () => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    return db.clear()
  }

  /**
   * 获取指定会话中聊天记录
   *
   * @param convId 会话ID
   * @returns
   */
  public getConvChatsHistory = async (convId: string) => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    const conv = await db.get(convId)
    if (conv) {
      return conv.chats
    }
    return []
  }

  /**
   * 获取指定聊天记录
   *
   * @param convId 会话ID
   * @param chatId 聊天ID
   * @returns
   */
  public getConvChatById = async (convId: string, chatId: string) => {
    const db = await StorageProvider.DBChatInstance<DbConvs>(ChatStoreName.Conversations)
    const conv = await db.get(convId)
    if (conv) {
      return conv.chats.find((item) => item.id === chatId)
    }
  }
}

export default xChatService
